local t_util = require "libs/tableutil"
local e_util = require "libs/entutil"
local c_util = require "libs/calcutil"
local l_data = require "QAQ/layoutdata"
local s_mana = require "libs/settingmanager"
local file_id = "more_map_tiles"
local setting = s_mana:GetSettingLine(file_id)
setting.show = type(setting.show) == "nil" and true or setting.show

local MapPrefabs = l_data.map_prefabs
local AlwayPrefabs = l_data.alway_prefabs
local MoreTiles = require "widgets/automaptiles"
local function genicon(self)
    if self.moremaptiles then
        self.moremaptiles:Kill()
    end
    self.moremaptiles = self:AddChild(MoreTiles(self, setting))
end
local function gethudtile()
    return GLOBAL.TheFrontEnd and GLOBAL.TheFrontEnd:GetActiveScreen() and GLOBAL.TheFrontEnd:GetActiveScreen().moremaptiles
end
-- 高端的加密往往只用朴素的方式
local whynum = {
    6, 8, 5, 7, 3, 1, 4, 2
}
local function ReFresh()
    if not setting.show then return end
    local w_util = require "libs/worldutil"
    local w_mana = require("libs/worldmanager")
    local w_data = w_mana:GetWorldDataMap(file_id)
    local w_setting = w_mana:GetWorldDataLine(file_id)


    local iscave = GLOBAL.TheWorld:HasTag("cave")
    local c = iscave and 1 or 0
    local dirs = iscave and l_data.infocave or l_data.infoday
    local seed = w_util:GetSeed() or c
    local room_ids = GLOBAL.TheWorld.topology and GLOBAL.TheWorld.topology.ids or {}
    local room_nodes = GLOBAL.TheWorld.topology and GLOBAL.TheWorld.topology.nodes or {}

    
    local function AddPrefabData(pos, prefab)
        local x, y = pos.x, pos.y
        if table.contains(AlwayPrefabs, prefab) or not GLOBAL.ThePlayer:CanSeePointOnMiniMap(x, 0, y) then
            w_data[c_util:GetPosID(x, y)] = {
                x = x,
                z = y,
                c = c,
                p = MapPrefabs[prefab] or prefab
            }
        end
    end
    local function AddPrefabsData(center_pos, prefabs, layout_data)
        if not center_pos then
            return
        end
        t_util:IPairs(prefabs, function(prefab)
            local prefab_data = layout_data[prefab]
            if prefab_data then
                t_util:IPairs(prefab_data, function(p_data)
                    local x, y = c_util:ModeToXY(whynum[center_pos.m], p_data.x*4, p_data.y*4, center_pos.x, center_pos.y)
                    AddPrefabData({
                        x = x,
                        y = y
                    }, prefab)
                end)
            end
        end)
    end

    
    local function ScanMap()
        local scanned = w_setting[seed]
        w_setting[seed] = true
        t_util:Pairs(w_data, function(id, data)
            if data and GLOBAL.ThePlayer:CanSeePointOnMiniMap(data.x, 0, data.z) and not table.contains(AlwayPrefabs, data.p) and data.c == c then
                w_data[id] = nil
            end
        end)

        local map_tile = w_util:GetMapTiles(true) or {}
        local function addTileIcon(tilename, range, icon, notcave)
            if notcave == iscave then
                return
            end
            local tiles = WORLD_TILES[tilename] and map_tile[WORLD_TILES[tilename]] or {}
            local range = range or 20
            local commus = c_util:CommusRec(tiles, range)
            t_util:IPairs(commus, function(data)
                AddPrefabData({
                    x = data.x1/2+data.x2/2,
                    y = data.y1/2+data.y2/2,
                }, icon)
            end)
        end

        local function addRoomIcon(name, prefab, notcave)
            if notcave == iscave then
                return
            end
            local node = t_util:GetElement(room_ids, function(id, r_name)
                return type(r_name)=="string" and r_name:lower():find(name:lower()) and id
            end)
            local pos = node and room_nodes[node]
            if pos then
                AddPrefabData({
                    x = pos.x,
                    y = pos.y,
                }, prefab)
            end
        end

        local function addRoomsIcon(name, prefab, notcave)
            if notcave == iscave then
                return
            end
            t_util:Pairs(room_ids, function(id, r_name)
                if type(r_name)=="string" and r_name:lower():find(name:lower()) then
                    local pos = room_nodes[id]
                    if pos then
                        AddPrefabData({
                            x = pos.x,
                            y = pos.y,
                        }, prefab)
                    end
                end
            end)
        end

        if scanned then
            addTileIcon("OCEAN_ICE", 20, "icefishing_hole", true)
        else
            t_util:Pairs(dirs, function(_, dir)
                local src = dir.src
                local tp_src = type(src)
                local tag = dir.tag
                if tp_src == "table" and type(src[1]) == "table" then
                    local pos_list = w_util:GetTilesResult(src, dir.deny)
                    if not pos_list then
                        return
                    end
        
                    if tag == "alone" then
                        local commus = c_util:CommuRec(pos_list, dir.range, true)
                        t_util:Pairs(commus, function(_, commu)
                            if #commu == 1 then
                                t_util:IPairs(dir.prefabs, function(prefab)
                                    AddPrefabData(commu[1], prefab)
                                end)
                            end
                        end)
                    elseif tag == "only" then
                        local a_data = pos_list[1]
                        if a_data then
                            print("捕获成功", a_data.x, a_data.y)
                        end
                    else
                        local commus = c_util:CommuRec(pos_list, dir.range)
                        local center_commu = c_util:GetCenterPos(commus)
                        t_util:IPairs(center_commu, function(pos)
                            t_util:IPairs(dir.prefabs, function(prefab)
                                AddPrefabData(pos, prefab)
                            end)
                        end)
                    end
                else
                    local srcs = tp_src == "string" and {src} or src
        
                    t_util:IPairs(srcs, function(src)
                        local result = w_util:GetLayoutResult(src, dir.deny, dir.enlarge)
                        if not result then
                            return
                        end
                        local layout_data = result.layout
                        if tag == "only" then
                            local _, c_pos = GLOBAL.next(result.pos_list)
                            AddPrefabsData(c_pos, dir.prefabs, layout_data)
                        elseif tag == "alone" then
                            local commus = c_util:CommuRec(result.pos_list, result.width, true)
                            t_util:Pairs(commus, function(_, commu)
                                if #commu == 1 then
                                    AddPrefabsData(commu[1], dir.prefabs, layout_data)
                                end
                            end)
                        else
                            t_util:IPairs(result.pos_list, function(pos)
                                AddPrefabsData(pos, dir.prefabs, layout_data)
                            end)
                        end
                    end)
                end
            end)
            addTileIcon("OCEAN_BRINEPOOL", 12, "saltstack", true)
            addTileIcon("OCEAN_WATERLOG", 20, "oceantree_pillar", true)
            addRoomIcon("beequeen", "beequeenhivegrown", true)
            addRoomIcon("walrus", "igloo", true)
            addRoomIcon("MoonBaseOne", "moonbase", true)
            addRoomIcon("MonkeyIsland", "monkeyqueen", true)
            addTileIcon("OCEAN_ICE", 20, "icefishing_hole", true)
            addRoomsIcon("CaveExitRoom", "cave_open2", false)
            addRoomsIcon("ToadstoolArenaMud", "toadstool_cap_dark", false)
            addRoomsIcon("ToadstoolArenaCave", "toadstool_cap_dark", false)
            addRoomsIcon("ToadstoolArenaCave", "toadstool_cap_dark", false)
            addRoomsIcon("MoonCaveForest", "mushtree_moon", false)
        end
    end

    ScanMap()
end
local function ShowMap()
    setting.show = not setting.show
    s_mana:SaveSettingLine(file_id, setting)
end
AddClassPostConstruct("screens/mapscreen", function(self)
    genicon(self)
    ReFresh()
    local _OnMouseButton = self.OnMouseButton
    function self.OnMouseButton(self, button, down, ...)
        if button == GLOBAL.MOUSEBUTTON_RIGHT and down then
            local mapbutton = t_util:GetChild(t_util:GetChild(t_util:GetChild(self, "br_root"), "br_scale_root"), "Map Controls")
            if mapbutton and mapbutton.focus then
                ShowMap()
            end
        end
        return _OnMouseButton(self, button, down, ...)
    end
end)
AddClassPostConstruct("screens/playerhud", genicon)
AddClassPostConstruct("widgets/mapcontrols", function(self)
    local btn = self.minimapBtn
    local _OnMouseButton = btn.OnMouseButton
    function btn.OnMouseButton(self, button, down, ...)
        if button == GLOBAL.MOUSEBUTTON_RIGHT and down then
            -- 适配全球定位
            if GLOBAL.TheFrontEnd and GLOBAL.TheFrontEnd:GetActiveScreen() and GLOBAL.TheFrontEnd:GetActiveScreen().name == "HUD" then
                ShowMap()
            end
        end
        return _OnMouseButton(self, button, down, ...)
    end
end)

local function fn()
    ShowMap()
    TIP("地图扫描", "white", setting.show)
end
-- 经典三行
if GetModConfigData("sw_mapscan") == "biubiu" then
    DEAR_BTNS:AddDearBtn("images/hud.xml", "map_button.tex", "地图扫描", "开启此功能后，手动点击地图按钮将扫描地皮，首次运行较慢", true, fn)
end
AddBindBtn("sw_mapscan", fn)
